#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>

// 仓颉关键字列表（适配测试用例）
const char* keywords[] = {"main", "var", "int", "float", "func", 
    "return", "const", "if", "else", "for", "in", "while", "do", 
	"break", "continue", "class", "struct", "import", "package", 
	"true", "false"
	};
	
int keywordCount = 21;
int len1 = 0;
char OutPut[1000];

bool _iskeyword(const char* token, int start, int end) {
	if(start == end) {
		if(strcmp(token, keywords[start])) return true;
		return false;
	}
	int mid = (start + end) / 2;
	return (_iskeyword(token, start, mid) || _iskeyword(token, mid + 1, end));	
}

// 判断是否是关键字
bool isKeyword(const char* token) {
   return _iskeyword(token, 0, keywordCount - 1);  
}

// 读取测试用例文件
char* readTestFile(const char* filename) {
    FILE* fp = fopen(filename, "rb");
    if (!fp) { perror("打开test.cangjie失败"); exit(1); }

    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    char* code = (char*)malloc(size + 1);
    fread(code, 1, size, fp);
    code[size] = '\0';
    fclose(fp);
    return code;
}

void lexAnalyze(const char* code) {
    int i = 0;
    int len = strlen(code);
    char tokenBuf[1000];
    int bufIdx = 0;
	int rol = 1;
    while (i < len) {
        // 跳过空白符
        if (isspace((unsigned char)code[i])) { 
			if((unsigned char)code[i] == '\n') rol++;
			i++; 
			continue; 
		}
        bufIdx = 0;
        // 处理字母（关键字/标识符：main/var/num1等）
        if (isalpha((unsigned char)code[i])) {
        	int j = bufIdx;
            while (i < len && !isspace((unsigned char)code[i])) {
                tokenBuf[bufIdx++] = code[i++];
            }
            tokenBuf[bufIdx] = '\0';
            int label = 0;
            while(j < bufIdx) {
				if(isalpha((unsigned char)tokenBuf[j]) || isdigit((unsigned char)tokenBuf[j])) {
					j++;
					continue;
				} else {
					printf("%s\n", tokenBuf);
					len1 += sprintf(OutPut + len1, "变量名出错了\n");
					j++;
					label = 1;
				}		
			}
			if(label) continue;
            if (isKeyword(tokenBuf)) {
                len1 += sprintf(OutPut + len1, "%s\t%s\n", tokenBuf, tokenBuf);
            } else {
                len1 += sprintf(OutPut + len1, "ID\t%s\n", tokenBuf);
            }
        }
        // 处理数字
        else if (isdigit((unsigned char)code[i])) {
        	
        	if(isalpha((unsigned char)code[i + 1])) {
				len1 += sprintf(OutPut + len1, "变量名出错了!\n");
				while(!isspace((unsigned char)code[i])) i++;
				continue;
			}
            while (i < len && (isdigit((unsigned char)code[i]) || code[i] == '.')) {
                tokenBuf[bufIdx++] = code[i++];
            }
            if(code[i - 1] == '.') {
				len1 += sprintf(OutPut + len1, "常数有问题!!!\n");
				break;	
			}
            tokenBuf[bufIdx] = '\0';
            len1 += sprintf(OutPut + len1, "NUM\t%s\n", tokenBuf);
        }
        //处理注释
		else if(code[i] == '/' && code[i + 1] == '*') {
			i += 2;
			while(code[i] != '*' && code[i + 1] != '/') {
				if((unsigned char)code[i] == '\n') rol++;
				i++;
			}
			i += 2;
		}
		// 处理运算符
        else if (code[i] == '=' || code[i] == '>' || code[i] == '<' || 
		         code[i] == '+' || code[i] == '-' || 
			     code[i] == '*' || code[i] == '/') {
			     	
			tokenBuf[bufIdx++] = code[i++];
			while(1) {
				if(code[i - 1] == '*' || code[i - 1] == '/') break;
				if(code[i] == '=') {
					tokenBuf[bufIdx++] = code[i++];
					break;
				}
				break;
			}
            tokenBuf[bufIdx] = '\0';
            len1 += sprintf(OutPut + len1, "%s\t%s\n", tokenBuf, tokenBuf);
        }
        // 处理分隔符
        else if (strchr("(){}:;", code[i])) {
            tokenBuf[bufIdx++] = code[i++];
            tokenBuf[bufIdx] = '\0';
			len1 += sprintf(OutPut + len1, "%s\t%s\n", tokenBuf, tokenBuf);  
        }
        // 未知符号
        else {
            len1 += sprintf(OutPut + len1, "第%d行: 非法单词\"%c\"\n", rol, code[i]);
            i++;
        }
	}
}

int main() {
    char* testCode = readTestFile("test.txt");
    len1 += sprintf(OutPut, "====== 词法分析结果 ======\n");
    lexAnalyze(testCode);
    free(testCode);
    printf("%s", OutPut);
    FILE* fp = fopen("Output.txt", "w");
    if(fp == NULL) { perror("打开失败"); exit(1); }
    fprintf(fp, OutPut);
    fclose(fp);
    return 0;
}